package junior.util;

import junior.util.value.ConvertParam;
import junior.util.value.ValueUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springframework.util.Assert;

import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BaseContext<K, V> {
    protected Map<K, V> ctxMap = new HashMap<K, V>();
    private ConvertParam convertParam = new ConvertParam().deepCopy(true);
    
    public void set(K key, V value) {
        ctxMap.put(key, value);
    }
    
    public V get(K key) {
        return ctxMap.get(key);
    }
    
    public <T> T get(K key, Class<T> typeClass) {
        Object value = this.get(key);
        if (value == null) return null;
        return convert(this.get(key), typeClass);
    }
    
    /**
     * 指定类型为数组
     * @param key
     * @param arrayClass 数组类型，如User[].class
     * @param <T>
     * @return
     */
    public <T> T[] getArray(K key, Class<?> arrayClass) {
        Assert.isTrue(arrayClass.isArray(), "arrayClass must be an array type");
        return (T[]) get(key, arrayClass);
    }
    
    public <T> List<T> getList(K key, Class<T> elementClass) {
        Object value = this.get(key);
        if (value == null) return null;
        return convert(this.get(key), TypeUtils.parameterize(List.class, elementClass));
    }
    
    public <Key, Value> Map<K, V> getMap(K key, Class<Key> keyClass, Class<Value> valueClass) {
        Object value = this.get(key);
        if (value == null) return null;
        return convert(this.get(key), TypeUtils.parameterize(Map.class, keyClass, valueClass));
    }
    
    public <Key, Value> List<Map<K, V>> getListMap(K key, Class<Key> keyClass, Class<Value> valueClass) {
        Object value = this.get(key);
        if (value == null) return null;
        return convert(this.get(key), TypeUtils.parameterize(List.class, TypeUtils.parameterize(Map.class, keyClass, valueClass)));
    }
    
    protected <T> T convert(V obj, Class<T> typeClass) {
        return ValueUtils.convert(obj, typeClass);
    }
    
    protected <T> T convert(V obj, ParameterizedType type) {
        return ValueUtils.convert(obj, type, convertParam);
    }
}
